package com.xdxc.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xdxc.emuns.GroupType;
import com.xdxc.emuns.QuestionType;
import com.xdxc.exception.CustomException;
import com.xdxc.feign.GradingFeign;
import com.xdxc.feign.QuestionFeign;
import com.xdxc.form.GradingResultForm;
import com.xdxc.mapper.ExamRecordMapper;
import com.xdxc.model.dto.*;
import com.xdxc.model.entity.*;
import com.xdxc.model.vo.QuestionWithGrading;
import com.xdxc.model.vo.UserAnswerVo;
import com.xdxc.response.Result;
import com.xdxc.service.ExamRecordService;
import com.xdxc.service.ExamsService;
import com.xdxc.service.PaperService;
import com.xdxc.service.QuestionGroupService;
import com.xdxc.utils.JWTUtil;
import com.xdxc.utils.RandomIdGenerator;
import com.xdxc.utils.SecurityUtils;
import com.xdxc.utils.TokenManager;
import com.xdxc.vo.AnswerVo;
import com.xdxc.vo.QuestionWithOptionsVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;


@Service
public class ExamRecordServiceImpl extends ServiceImpl<ExamRecordMapper, ExamRecord> implements ExamRecordService {
    @Autowired
    private PaperService paperService;

    @Autowired
    private ExamsService examsService;

    @Autowired
    private QuestionGroupService questionGroupService;


    @Autowired
    private  RedisService redisService;

    @Autowired
    private QuestionFeign questionFeign;

    @Autowired
    private GradingFeign gradingFeign;



    @Autowired
    private TokenManager tokenManager;

    @Override
    @Cacheable(value = "paperDetail", key = "#paperId", unless = "#result == null")
    public Result<?> getPaperDetail(Long paperId) {
        // 1. 查询考生考试记录
        ExamRecord examRecord = this.getOne(new LambdaQueryWrapper<ExamRecord>()
                .eq(ExamRecord::getId, paperId));
        if (examRecord == null) {
            return null;
        }

        // 2. 并行查询考试信息和试卷题目
        CompletableFuture<Exams> examsFuture = CompletableFuture.supplyAsync(() ->
                examsService.getById(examRecord.getExamId()));

        CompletableFuture<List<Paper>> papersFuture = CompletableFuture.supplyAsync(() ->
                paperService.list(new LambdaQueryWrapper<Paper>()
                        .eq(Paper::getPaperId, examRecord.getPaperId())));

        // 等待所有并行任务完成
        CompletableFuture.allOf(examsFuture, papersFuture).join();

        Exams exams = examsFuture.join();
        List<Paper> paperList = papersFuture.join();

        if (paperList.isEmpty()) {
            return Result.success(exams);
        }

        // 3. 获取用户答案
        GradingResultForm gradingResultForm = new GradingResultForm();
        gradingResultForm.setUserId(SecurityUtils.getCurrentUserId());
        gradingResultForm.setPaperId(paperId);

        Map<Long, UserAnswerVo> userAnswerVoMap = handleFeignResult(gradingFeign.getGradingResult(gradingResultForm))
                .stream()
                .collect(Collectors.toMap(
                        UserAnswerVo::getCheckId,
                        Function.identity(),
                        (existing, replacement) -> replacement));
        // 4. 获取题目详情
        List<Long> questionsId = paperList.stream()
                .map(Paper::getQuId)
                .distinct() // 使用 distinct() 替代 Collectors.toSet() 转换
                .collect(Collectors.toList());
        String token=tokenManager.getToken();
        Map<Long, QuestionWithOptionsVo> questionWithOptionsVoMap = handleFeignResult(
                questionFeign.getBatchQuestions("Bearer "+token,questionsId))
                .stream()
                .collect(Collectors.toMap(QuestionWithOptionsVo::getId, Function.identity()));

        // 5. 组装结果
        List<QuestionWithGrading> questionWithOptionsVoList = paperList.stream()
                .map(paper -> convertToQuestionWithGrading(
                        paper,
                        questionWithOptionsVoMap.get(paper.getQuId()),
                        userAnswerVoMap.get(paper.getId())
                )).collect(Collectors.toList());

        return Result.success(this.groupQuestions(questionWithOptionsVoList, exams, examRecord));
    }

    private <T> T handleFeignResult(Result<T> result) {
        if (result.getCode() != 1) {
            throw new CustomException(result.getCode(), result.getMsg());
        }
        return result.getData();
    }

    private QuestionWithGrading convertToQuestionWithGrading(Paper paper,
                                                             QuestionWithOptionsVo questionVo,
                                                             UserAnswerVo userAnswer) {
        QuestionWithGrading questionWithGrading = new QuestionWithGrading();
        questionWithGrading.setContent(questionVo.getContent());
        questionWithGrading.setImage(questionVo.getImage());
        questionWithGrading.setManual(questionVo.getManual());
        questionWithGrading.setAnalysis(questionVo.getAnalysis());
        questionWithGrading.setAnswerOrder(questionVo.getAnswerOrder());
        questionWithGrading.setCorrectAnswerVo(questionVo.getCorrectAnswerVo());
        questionWithGrading.setId(questionVo.getId());
        questionWithGrading.setQuId(questionVo.getQuId());
        questionWithGrading.setQuType(questionVo.getQuType());
        questionWithGrading.setQuTypeDictText(questionVo.getQuTypeDictText());
        questionWithGrading.setAnswerVoList(questionVo.getAnswerVoList());
        questionWithGrading.setSubList(questionVo.getSubList());
        questionWithGrading.setScore(paper.getScore());
        questionWithGrading.setSort(paper.getSort());
        questionWithGrading.setCheckId(paper.getId());
        questionWithGrading.setUserAnswer(userAnswer);
        return questionWithGrading;
    }
    @Override
    public ExamingDto returnPaperData(Long paperId) {
        // 获取考试记录
        ExamRecord examRecord = this.getOne(new LambdaQueryWrapper<ExamRecord>().eq(ExamRecord::getId, paperId));
        if (examRecord == null) {
           throw new CustomException(400,"没有试卷被找到");
        }
        // 获取题组列表
        List<QuestionGroupDto> questionGroupList = questionGroupService
                .list(new LambdaQueryWrapper<QuestionGroup>().eq(QuestionGroup::getPaperId,examRecord.getPaperId()))
                .stream().map(questionGroup -> {
                    QuestionGroupDto questionGroupDto = new QuestionGroupDto();
                    BeanUtils.copyProperties(questionGroup,questionGroupDto);
                    return questionGroupDto;
                }).collect(Collectors.toList());
        if (questionGroupList.isEmpty()) {
            throw new CustomException(400,"No Question Groups found.");
        }

        // 获取所有试卷
        List<Paper> paperList = paperService.returnPaperWithUserAnswer(examRecord.getId(),examRecord.getPaperId());
        if (paperList.isEmpty()) {
            throw new CustomException(400,"No Question Groups found.");
        }
        // 将试卷按组分配，并对每组内的试卷按 Sort 字段排序
        Map<Long, List<Paper>> optionsMap = paperList.stream()
                .peek(paper -> {
                    // Change field values here
                    paper.setPaperId(paperId);  // Modify the title field
                })
                .sorted(Comparator.comparing(Paper::getSort))  // Sort by Sort field
                .collect(Collectors.groupingBy(Paper::getGroupId));  // Group by GroupId
        List<QuestionGroupDto> questionGroupList1 = new ArrayList<>();
        for (QuestionGroupDto group : questionGroupList) {
            List<Paper> papersInGroup = optionsMap.get(group.getId());
            if (papersInGroup != null && !papersInGroup.isEmpty()) {
                // 对每组内的试卷按照 Sort 字段再次排序
                papersInGroup.sort(Comparator.comparing(Paper::getSort));
                QuestionGroupDto questionGroup = new QuestionGroupDto();
                questionGroup.setId(group.getId());
                questionGroup.setPaperId(paperId);
                questionGroup.setQuType(group.getQuType());
                questionGroup.setTitle(group.getTitle());
                questionGroup.setQuList(papersInGroup);
                questionGroup.setTotalScore(getTotalScore(papersInGroup));
                questionGroup.setQuTypeDictText(group.getQuTypeDictText());
                questionGroupList1.add(questionGroup);
            }
        }
        // 获取考试对象
        Exams exams = examsService.getOne(new LambdaQueryWrapper<Exams>().eq(Exams::getId, examRecord.getExamId()));
        if (exams == null) {
            throw new CustomException(400,"No Question Groups found.");
        }
        ExamingDto examingDto = new ExamingDto();
        BeanUtils.copyProperties(exams,examingDto);

        examingDto.setQuestionGroupList(questionGroupList1);
        examingDto.setPaperId(examRecord.getId());
        examingDto.setDuration(exams.getDuration());
        examingDto.setPaperId(examRecord.getId());
        examingDto.setTotalTime(examRecord.getTotalTime());
        return examingDto;
    }

    @Override
    public Result getQuestionById(Long id, Long paperId) {
        // 1. 使用更清晰的变量命名
        ExamRecord examRecord = this.getOne(
                new LambdaQueryWrapper<ExamRecord>().eq(ExamRecord::getId, paperId)
        );
        if (examRecord == null) {
            throw new CustomException(400,"不是当前考试");
        }
        // 获取所有匹配的记录
        Paper paper = paperService.getOne(new LambdaQueryWrapper<Paper>().eq(Paper::getId,id));
        if (paper == null) {
            throw new CustomException(400,"题目不在试卷内");

        }
        Long quId=paper.getQuId();
        // 3. 使用批量查询优化性能
        Long time= (long) (60*60*60);
        List<String> roles=new ArrayList<>();
        roles.add("TEACHER");
        Result<QuestionWithOptionsVo> result= questionFeign.getQuestion( "Bearer " + JWTUtil.generateToken( "User" ,SecurityUtils.getCurrentUserId(),roles,time),quId);

        if (result.getCode()!=1) {
         throw new CustomException(400,"题目信息有误");
        }
        QuestionWithOptionsVo questionWithOptions=result.getData();
        QuestionDto questionDto=   buildQuestions(questionWithOptions,paper,paperId,examRecord.getExamId());
        return Result.success(questionDto);
    }


    private QuestionDto buildQuestions(QuestionWithOptionsVo questionWithOption, Paper paper, Long paperId,Long examId){
        QuestionDto questionDto = new QuestionDto();
        questionDto.setContent(questionWithOption.getContent());
        questionDto.setId(questionWithOption.getId());
        questionDto.setQuType(questionWithOption.getQuType());
        questionDto.setQuId(questionWithOption.getQuId());
        questionDto.setImage(questionWithOption.getImage());
        questionDto.setCheckId(paper.getId());
        questionDto.setPaperId(paperId);
        questionDto.setManual(questionWithOption.getManual());
        questionDto.setQuTypeDictText(questionWithOption.getQuTypeDictText());
        questionDto.setScore(paper.getScore());
        questionDto.setExamId(examId);
        questionDto.setAnswerList( convertToDto(questionWithOption.getAnswerVoList(),paperId, paper));
        return questionDto;
    }

    private List<AnswerDto> convertToDto(List<AnswerVo> answers, Long paperId, Paper paper) {

        Comparator<AnswerDto> descComparator = Comparator.comparing(
                AnswerDto::getSort,
                Comparator.nullsLast(Comparator.naturalOrder())
        );
        Long userId= SecurityUtils.getCurrentUserId();
        UserAnswer userAnswer= (UserAnswer)redisService.getField(paperId+"_"+userId, String.valueOf(paper.getId()));
        // 如果 userAnswersMap 为空，初始化一个空的 HashMap
        List<AnswerDto>  answerDtoList=  answers.stream()
                .map(answer -> {
                    AnswerDto dto = new AnswerDto();
                    dto.setAbc(answer.getAbc());
                    dto.setId(answer.getId());
                    dto.setSort(answer.getSort());
                    dto.setContent(answer.getContent());
                    dto.setImage(answer.getImage());
                    dto.setPaperId(paperId);
                    dto.setScoreRate(answer.getScoreRate());
                    dto.setQuId(answer.getQuId());
                    dto.setCheckId(paper.getId());
                    // 8. 处理用户答案数据
                    if (userAnswer != null) {
                        dto.setChecked(userAnswer.getAnswerIds().contains(answer.getId()));
                        dto.setAnswer(userAnswer.getAnswerText());
                    } else {
                        dto.setAnswer("");
                        dto.setChecked(false);
                    }
                    dto.setIsRight(null); // 明确设置默认值
                    return dto;
                }).sorted(descComparator)
                .collect(Collectors.toList());
        return answerDtoList;
    }
    public  Double getTotalScore(List<Paper> paperList) {
        Double totalScore=0.0;
        for ( Paper paper :  paperList) {
            totalScore+= paper.getScore();
        }
        return totalScore;

    }
    @Override
    public Long createExamRecord(Long examId, Long userId){
        Exams exam= examsService.getOne( new LambdaQueryWrapper<Exams>().eq(Exams::getId,examId));
        if (exam==null){
            throw new CustomException(400,"没有找到考试");
        }
        ExamRecord examRecord = new ExamRecord();
        RandomIdGenerator randomIdGenerator = new RandomIdGenerator(1,6);
        Long id=randomIdGenerator.generateId();
        examRecord.setId(id);
        examRecord.setUserId(userId);
        examRecord.setExamId(exam.getId());
        examRecord.setPaperId(exam.getPaperId());
        boolean saved = this.save(examRecord);
        if (!saved){
            throw new CustomException(400,"错误");
        }
        boolean bo=  redisService.set("exam:" +SecurityUtils.getCurrentUserId(), id, exam.getDuration()+ 180);

        if (!bo){
          throw new CustomException(405,"服务器错误，稍后重试");
        }
        return id;
    }



    public ExamResultDTO groupQuestions(List<QuestionWithGrading> questions,Exams exam,ExamRecord examRecord) {
        // 1. 先按quType分组
        Map<Integer, List<QuestionWithGrading>> groupedByType = questions.stream()
                .collect(Collectors.groupingBy(QuestionWithGrading::getQuType));


        List<GroupQuestion>  groupQuestion=groupedByType.entrySet().stream()
                .map(entry -> {
                    int typeCode = entry.getKey();
                    return new GroupQuestion(
                            UUID.randomUUID().toString(),  // 生成随机ID
                            String.valueOf(QuestionType.getName(typeCode)),
                            String.valueOf(GroupType.getName(typeCode)) , // 题型名称
                            entry.getValue()               // 题目列表
                    );
                })
                .collect(Collectors.toList());

        ExamResultDTO examResultDTO=new ExamResultDTO();

        examResultDTO.setExamName(exam.getTitle());
        examResultDTO.setTotalScore(exam.getTotalScore());
        examResultDTO.setId(exam.getId());
        examResultDTO.setEndTime(exam.getEndTime());
        examResultDTO.setPassScore(   exam.getPassScore() != null
                ? BigDecimal.valueOf(exam.getPassScore())
                : null);
        examResultDTO.setObjectiveScore(
                examRecord.getObjScore() != null
                        ? BigDecimal.valueOf(examRecord.getObjScore())
                        : null
        );

        examResultDTO.setSubjectiveScore(
                examRecord.getObjScore() != null
                        ? BigDecimal.valueOf(examRecord.getObjScore())
                        : null
        );
        examResultDTO.setStartTime(exam.getStartTime());

        examResultDTO.setQuestionGroupList(groupQuestion);
        // 2. 转换为QuestionGroup列表
        return examResultDTO;
    }
}
